﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;

namespace Kernel
{
    public class Common
    {
        /// <summary>
        /// 将块表记录加入到块表中
        /// </summary>
        /// <param name="btr">块表记录</param>
        /// <param name="db">数据库</param>
        /// <returns>块表记录 ObjectId</returns>
        public static ObjectId AppendBtrToBlockTable( BlockTableRecord btr, Database db)
        {
            ObjectId id = new ObjectId();

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                id = bt.Add(btr);
                tr.AddNewlyCreatedDBObject(btr, true);

                tr.Commit();
            }
            return id;
        }

        public static ObjectId AppendBtrToBlockTable(BlockTableRecord record)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            ObjectId id;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                id = bt.Add(record);
                tr.AddNewlyCreatedDBObject(record, true);

                tr.Commit();
            }
            return id;
        }

        /// <summary>
        /// 创建属性
        /// </summary>
        /// <param name="label">标记名</param>
        /// <param name="prompt">提示</param>
        /// <param name="value">属性值</param>
        /// <param name="pt">属性插入点</param>
        /// <returns>属性</returns>
        public static AttributeDefinition AttributeDefinition(string label, string prompt, string value, Point3d pt)
        {
            AttributeDefinition ad = new Autodesk.AutoCAD.DatabaseServices.AttributeDefinition();
            ad.Constant = false;
            ad.Tag = label;
            ad.Prompt = prompt;
            ad.TextString = value;
            ad.Position = pt;
            return ad;
        }

        /// <summary>
        /// 将块定义创建块引用，并添加到模型空间(ModelSapce)
        /// </summary>
        /// <param name="blkid"></param>
        /// <param name="pt"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static ObjectId AppendBlkAttToModelSpace( ObjectId blkid, Point3d pt, Database db)
        {
            ObjectId blk_rf_id = new ObjectId();

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                BlockTableRecord btr_ms = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                BlockTableRecord block = tr.GetObject(blkid, OpenMode.ForRead) as BlockTableRecord;
                BlockReference br = new BlockReference(pt, blkid);//通过块定义，添加块参照
                blk_rf_id = btr_ms.AppendEntity(br);//将块参照添加到块表记录
                tr.AddNewlyCreatedDBObject(br, true);//通过事务添加块参照到数据库


                foreach (ObjectId id in block)
                {   
                    if (id.GetObject(OpenMode.ForRead).GetType().Equals(typeof(AttributeDefinition)))
                    {
                        AttributeDefinition ad = tr.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
                        AttributeReference ar = new AttributeReference(ad.Position, ad.TextString, ad.Tag, new ObjectId());
                        br.AttributeCollection.AppendAttribute(ar);
                    }
                }

                tr.Commit();
            }
            return blk_rf_id;
        }

        /// <summary>
        /// 得到当前活动文档的扩展名
        /// </summary>
        /// <returns></returns>
        public static string GetDocType(Document doc)
        {
            string filTyp = null;
            if (null != doc)
            {
                FileInfo fi = new FileInfo(doc.Name);
                filTyp = fi.Extension;
            }

            return filTyp;
        }

        /// <summary>
        /// 得到当前活动文档名称
        /// </summary>
        /// <returns></returns>
        public static string GetDocName( Document doc )
        {
            string filName = null;
            if (null != doc)
            {
                FileInfo fi = new FileInfo(doc.Name);
                filName = fi.Name;
            }

            return filName;
        }

        /// <summary>
        /// 得到当前活动文档路径
        /// </summary>
        /// <returns></returns>
        public static string GetDocPath(Document doc)
        {
            string path = null;
            if (null != doc)
            {
                FileInfo fi = new FileInfo(doc.Name);
                path = fi.DirectoryName;
            }

            return path;
        }

        /// <summary>
        /// 得到当前活动文档的完整路径及名称
        /// </summary>
        /// <returns></returns>
        public static string GetDocFullName(Document doc)
        {
            string path = null;
            if (null != doc)
                path = doc.Name;

            return path;
        }

        /// <summary>
        /// 得到当前活动文档名称
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentActiveDocName()
        {
            string filName = null;
            Document doc = Core.GetCurrentActiveDoc();
            if (null != doc)
            {
                FileInfo fi = new FileInfo(doc.Name);
                filName = fi.Name;
            }

            return filName;
        }

        /// <summary>
        /// 得到当前活动文档路径
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentActiveDocPath()
        {
            string path = null;
            Document doc = Core.GetCurrentActiveDoc();
            if (null != doc)
            {
                FileInfo fi = new FileInfo(doc.Name);
                path = fi.DirectoryName;
            }

            return path;
        }

        /// <summary>
        /// 得到当前活动文档的完整路径及名称
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentActiveDocFullName()
        {
            string path = null;
            Document doc = Core.GetCurrentActiveDoc();
            if (null != doc)
                path = doc.Name;

            return path;
        }

        /// <summary>
        /// 枚举当前数据库下的全部块引用
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static List<BlockReference> ListAllBlockReference( Database db )
        {
            List<BlockReference> lst_blk_ref = new List<BlockReference>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                BlockTableRecord btr_ms = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                int i = 0;
                foreach (ObjectId btr_id in bt)
                {
                    BlockTableRecord bt_recd = tr.GetObject(btr_id, OpenMode.ForRead) as BlockTableRecord;
                    if (null != bt_recd)
                    {
                        int j = 0;
                        foreach (ObjectId ent_id in bt_recd)
                        {
                            if (ent_id.GetObject(OpenMode.ForRead).GetType().Equals(typeof(BlockReference)))
                            {
                                BlockReference blk_ref = tr.GetObject(ent_id, OpenMode.ForRead) as BlockReference;

                                /*将块引用添加到链表*/
                                lst_blk_ref.Add(blk_ref);
                            }
                            j++;
                        }
                    }
                    i++;
                }

                tr.Commit();
            }

            return lst_blk_ref;
        }

        /// <summary>
        /// 枚举当前数据库下的全部块引用
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static List<BlockReference> ListAllBlockReference(Database db,OpenMode openMode)
        {
            List<BlockReference> lst_blk_ref = new List<BlockReference>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, openMode);
                BlockTableRecord btr_ms = tr.GetObject(bt[BlockTableRecord.ModelSpace], openMode) as BlockTableRecord;
                int i = 0;
                foreach (ObjectId btr_id in bt)
                {
                    BlockTableRecord bt_recd = tr.GetObject(btr_id, OpenMode.ForRead) as BlockTableRecord;
                    if (null != bt_recd)
                    {
                        int j = 0;
                        foreach (ObjectId ent_id in bt_recd)
                        {
                            if (ent_id.GetObject(OpenMode.ForRead).GetType().Equals(typeof(BlockReference)))
                            {
                                BlockReference blk_ref = tr.GetObject(ent_id, openMode) as BlockReference;

                                /*将块引用添加到链表*/
                                lst_blk_ref.Add(blk_ref);
                            }
                            j++;
                        }
                    }
                    i++;
                }

                tr.Commit();
            }

            return lst_blk_ref;
        }

        /// <summary> 
        /// 获取数据库模型空间的所有图元 
        /// </summary> 
        public static ObjectIdCollection GetDbModelSpaceEntities(Database db)
        {
            ObjectIdCollection oids = new ObjectIdCollection();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTbl = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord modelSpace = tr.GetObject(blockTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
                foreach (ObjectId oid in modelSpace)
                {
                    DBObject dbobj = tr.GetObject(oid, OpenMode.ForRead);
                    if (dbobj is Entity)
                    {
                        oids.Add(oid);
                    }
                }
            }

            return oids;
        }

        /// <summary>
        /// 将制定Dwg文件的内容拷贝到制定的数据空间
        /// </summary>
        /// <param name="doc">目标文档</param>
        /// <param name="file_r">源文档路径</param>
        /// <param name="mode">模式 Raw:直接拷贝 Block:拷贝为块 BlockRef:拷贝为块引用</param>
        /// <param name="blockName">块的名称，当为Raw模式时，可以为“”，如果其它模式为“”，则默认为GUID</param>
        public static void DwgFileClone( Document doc, FileInfo file_r, DwgFileCloneMode mode, string blockName )
        {
            //检查blockName的值
            if ((blockName == null) || (blockName.Equals("") == true))
                blockName = Guid.NewGuid().ToString();

            Database db = doc.Database;

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                switch (mode)
                {
                    case DwgFileCloneMode.Raw://直接拷贝
                        using (Database srcDb = new Database(false, false))
                        {
                            srcDb.ReadDwgFile(file_r.FullName, FileOpenMode.OpenForReadAndReadShare, true, "");
                            ObjectIdCollection oids = Common.GetDbModelSpaceEntities(srcDb);//获取所有图元
                            if (oids.Count > 0)
                            {
                                IdMapping idMap = new IdMapping();
                                srcDb.WblockCloneObjects(oids, db.CurrentSpaceId, idMap, DuplicateRecordCloning.Ignore, false);//克隆图元
                            }
                        }
                        break;
                    case DwgFileCloneMode.Block://拷贝为块
                        using (Database srcDb = new Database(false, false))
                        {
                            BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
                            BlockTableRecord blk = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;//得到模型空间的块表记录
                            //将数据文件读入内存
                            srcDb.ReadDwgFile(file_r.FullName, FileOpenMode.OpenForReadAndReadShare, true, "");
                            //以块的形式将数据存入目标数据库
                            ObjectId blockId = db.Insert(blockName, srcDb, false);
                            //创建当前块的一个块引用
                            using (BlockReference br = new BlockReference(Point3d.Origin, blockId))
                            {
                                blk.AppendEntity(br);//将块引用添加到模型空间
                                trans.AddNewlyCreatedDBObject(br, true);
                            }
                        }
                        break;
                    case DwgFileCloneMode.BlockRef://拷贝为块引用
                        {
                            BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                            BlockTableRecord modelSpace = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

                            ObjectId refid = db.OverlayXref(file_r.FullName, blockName);//把外部文件转换为块文件
                            BlockReference br = new BlockReference(Point3d.Origin, refid);//通过块定义创建块参照
                            modelSpace.AppendEntity(br);//把块参照添加到块表记录
                            trans.AddNewlyCreatedDBObject(br, true);
                        }
                        break;
                }

                trans.Commit();
            }
        }

        /// <summary>
        /// 新建一个单行文本
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="pos">位置</param>
        /// <param name="height">高度</param>
        /// <param name="rot">旋转</param>
        /// <param name="isfield">是否是域</param>
        /// <returns>DBText对象</returns>
        public static DBText NewDBText( string str, Point3d pos, double height ,double rot, bool isfield)
        {
            DBText txt = new DBText();
            txt.Position = pos;
            txt.Height = height;
            txt.Rotation = rot;
            txt.WidthFactor = 0.7;

            if( true == isfield)
            {
                Field field = new Field(str);
                txt.SetField(field);
            }else
            {
                txt.TextString = str;
            }

            return txt;
        }

        public enum DwgFileCloneMode
        {
            Raw,
            Block,
            BlockRef
        }
    }
}
